package com.cskaoyan.wordmemorize.common.aspect.operate;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Sequence;
import com.cskaoyan.wordmemorize.auth.StpKit;
import com.cskaoyan.wordmemorize.dao.entity.OperateLogDO;
import com.cskaoyan.wordmemorize.dao.mapper.OperateLogMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.time.LocalDateTime;

/**
 * 操作日志切面类
 * 用于记录员工在后台的操作日志
 */
@Aspect
@Component
@Slf4j
public class OperateLogAspect {

    // MyBatis-Plus 雪花算法 Sequence 实例
    private static final Sequence sequence = new Sequence(1, 1);
    @Autowired
    private OperateLogMapper operateLogMapper;

    /**
     * 定义切点：所有带有@OperateLog注解的方法
     */
    @Pointcut("@annotation(OperateLog)")
    public void operateLogPointcut() {
    }

    /**
     * 环绕通知：记录操作日志
     */
    @Around("operateLogPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取方法签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        // 获取注解信息
        OperateLog operateLog = method.getAnnotation(OperateLog.class);
        if (operateLog == null) {
            return joinPoint.proceed();
        }

        // 获取当前登录员工ID
        Long employeeId = null;
        try {
            employeeId = StpKit.ADMIN.getLoginIdAsLong();
        } catch (Exception e) {
            log.warn("获取当前登录员工ID失败: {}", e.getMessage());
        }

        // 创建操作日志对象
        OperateLogDO operateLogDO = new OperateLogDO();
        // 使用雪花算法生成ID
        operateLogDO.setId(sequence.nextId());
        operateLogDO.setEmployeeId(employeeId);
        operateLogDO.setDataType(operateLog.dataType());
        operateLogDO.setOperateType(operateLog.operateType());
        operateLogDO.setCreateTime(Timestamp.valueOf(LocalDateTime.now()));

        Object result = null;
        String dataJson = "";

        try {
            // 执行原方法
            result = joinPoint.proceed();

            // 设置操作状态为成功
            operateLogDO.setStatus(1);

            // 根据操作类型和配置决定记录什么数据
            dataJson = buildDataJson(operateLog, joinPoint.getArgs(), result);

        } catch (Exception e) {
            // 设置操作状态为失败
            operateLogDO.setStatus(0);

            // 记录异常信息
            dataJson = JSON.toJSONString(new ErrorInfo(e.getClass().getSimpleName(), e.getMessage()));

            // 重新抛出异常
            throw e;
        } finally {
            // 设置data字段
            operateLogDO.setData(dataJson);

            // 保存操作日志
            try {
                operateLogMapper.insert(operateLogDO);
                log.info("操作日志记录成功: employeeId={}, dataType={}, operateType={}",
                        employeeId, operateLog.dataType(), operateLog.operateType());
            } catch (Exception e) {
                log.error("保存操作日志失败: {}", e.getMessage(), e);
            }
        }

        return result;
    }

    /**
     * 构建data字段的JSON字符串
     */
    private String buildDataJson(OperateLog operateLog, Object[] args, Object result) {
        StringBuilder dataBuilder = new StringBuilder();

        // 根据操作类型决定记录内容
        int operateType = operateLog.operateType();

        if (operateType == OperateLogConstant.OPERATE_ADD ||
                operateType == OperateLogConstant.OPERATE_UPDATE ||
                operateType == OperateLogConstant.OPERATE_UPDATE_STATUS) {
            // 新增、修改、修改状态：记录请求参数
            if (operateLog.logRequestParams() && args != null && args.length > 0) {
                dataBuilder.append(JSON.toJSONString(args[0]));
            }
        } else if (operateType == OperateLogConstant.OPERATE_SINGLE_DELETE ||
                operateType == OperateLogConstant.OPERATE_BATCH_DELETE) {
            // 删除操作：记录返回值（删除的对象信息）
            if (operateLog.logReturnValue() && result != null) {
                dataBuilder.append(JSON.toJSONString(result));
            }
        } else if (operateType == OperateLogConstant.OPERATE_EXCEL_ADD) {
            // Excel导入：记录返回值（导入结果）
            if (operateLog.logReturnValue() && result != null) {
                dataBuilder.append(JSON.toJSONString(result));
            }
        }

        // 添加操作描述
        if (StringUtils.hasText(operateLog.description())) {
            if (dataBuilder.length() > 0) {
                dataBuilder.append("; ");
            }
            dataBuilder.append(operateLog.description());
        }

        return dataBuilder.length() > 0 ? dataBuilder.toString() : "无详细数据";
    }

    /**
     * 错误信息内部类
     */
    private static class ErrorInfo {
        private String errorType;
        private String errorMessage;

        public ErrorInfo(String errorType, String errorMessage) {
            this.errorType = errorType;
            this.errorMessage = errorMessage;
        }

        public String getErrorType() {
            return errorType;
        }

        public void setErrorType(String errorType) {
            this.errorType = errorType;
        }

        public String getErrorMessage() {
            return errorMessage;
        }

        public void setErrorMessage(String errorMessage) {
            this.errorMessage = errorMessage;
        }
    }
}
